#include <windows.h>
#include <gl/glut.h>
#include "Camera.h"

void Camera::slide(float x, float y, float z)
{
	Vector3 slide = Vector3(x,y,z);
	Vector3 addedSlide = u.scale(x).add(v.scale(y).add(n.scale(z)));
	pos.setVector(pos.add(addedSlide));		//adjust the position of the camera

	applyView();
}

void Camera::setCamera(Vector3 Pos, Vector3 U, Vector3 V, Vector3 N)
{
	pos = Pos;
	u = U.calcNormalVect();
	v = V.calcNormalVect();
	n = N.calcNormalVect();

	applyView();
}

void Camera::setView(float ViewingAngle, float ScreenRatio, float CloseScreen, float FarScreen)
{
	viewingAngle = ViewingAngle;
	screenRatio = ScreenRatio;
	closeScreen = CloseScreen;
	farScreen = FarScreen;
	applyView();
}

void Camera::applyView()
{
	glLoadIdentity();
	gluPerspective(viewingAngle, screenRatio, closeScreen, farScreen);
	gluLookAt(	pos.getX(), pos.getY(), pos.getZ(),									// Eye
				pos.getX() - n.getX(),pos.getY() - n.getY(),pos.getZ() - n.getZ(),	// Center
				v.getX(),v.getY(),v.getZ());										// Up
}

void Camera::pitch(float angle)
{
	rotate(u, angle);
}

void Camera::yaw(float angle)
{
	rotate(v, angle);
}

void Camera::roll(float angle)
{
	rotate(n, angle);
}

void Camera::setViewingAngle(float angle)
{
	viewingAngle = angle;
	applyView();
}

void Camera::setScreenRatio(float angle)
{
	screenRatio = angle;
	applyView();
}

void Camera::rotate(Vector3 axis, float angle)
{
	angle = 3.14159265/180 * angle;

	//normalize the vector
	axis.setVector(axis.calcNormalVect());

	//setup commonly used trig calculations
	float CosTheta = cos(angle);
	float OneMinusCos = 1-CosTheta;
	float SinTheta = sin(angle);

	//setup quick access axis variables
	float axisX = axis.getX();
	float axisY = axis.getY();
	float axisZ = axis.getZ();

	//setup the individual values for the rotation vector of u
	float rotX = u.getX();
	float rotY = u.getY();
	float rotZ = u.getZ();

	// multiply the vector u with the rotation matrix
	u.setVector( rotX*(CosTheta+axisX*axisX*OneMinusCos) + 
						rotY*(axisX*axisY*OneMinusCos-axisZ*SinTheta) + 
						rotZ*(axisX*axisZ*OneMinusCos+axisY*SinTheta),
					rotX*(axisY*axisX*OneMinusCos+axisZ*SinTheta) + 
						rotY*(CosTheta+axisY*axisY*OneMinusCos) + 
						rotZ*(axisY*axisZ*OneMinusCos-axisX*SinTheta),
					rotX*(axisZ*axisX*OneMinusCos-axisY*SinTheta) + 
						rotY*(axisZ*axisY*OneMinusCos+axisX*SinTheta) + 
						rotZ*(CosTheta+axisZ*axisZ*OneMinusCos));
	
	//setup the individual values for the rotation vector of v
	rotX = v.getX();
	rotY = v.getY();
	rotZ = v.getZ();
	
	// multiply the vector v with the rotation matrix
	v.setVector( rotX*(CosTheta+axisX*axisX*OneMinusCos) + 
						rotY*(axisX*axisY*OneMinusCos-axisZ*SinTheta) + 
						rotZ*(axisX*axisZ*OneMinusCos+axisY*SinTheta),
					rotX*(axisY*axisX*OneMinusCos+axisZ*SinTheta) + 
						rotY*(CosTheta+axisY*axisY*OneMinusCos) + 
						rotZ*(axisY*axisZ*OneMinusCos-axisX*SinTheta),
					rotX*(axisZ*axisX*OneMinusCos-axisY*SinTheta) + 
						rotY*(axisZ*axisY*OneMinusCos+axisX*SinTheta) + 
						rotZ*(CosTheta+axisZ*axisZ*OneMinusCos));
	
	//normalize all vectors
	u.setVector(u.calcNormalVect());
	v.setVector(v.calcNormalVect());
	n = u.cross(v);

	applyView();
}